package work;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import tool.MatchesFinder;
import tool.RegexReader;

public class RelationExtractor {
	private HashMap<String, String> TrainingSet;
	private HashMap<String, String> LCMCSet;
	private XmlGenerator XmlGen;
	private final String LCMC_Attr = "^p$|^v$|^a$|^n$|^vn$|^m$";
	private final String TempFile = "RETemp.xml";
	private final String RegexFile = "RERegex.xml";
	private RegexReader regexReader;
	private HashSet<RelationEntity> RelationSet;

	public RelationExtractor(HashMap<String, String> _training_set,
			HashMap<String, String> _lcmc_set, XmlGenerator _xml_gen) {
		TrainingSet = _training_set;
		LCMCSet = _lcmc_set;
		XmlGen = _xml_gen;
		regexReader = new RegexReader();
		RelationSet = new HashSet<RelationEntity>();
	}

	public void extract(String input_file, String marked_file) throws Exception {
		markInput(input_file, marked_file);
		MatchesFinder.process(marked_file, TempFile, RegexFile);
		processPattern(TempFile);
		for(RelationEntity re : RelationSet){
			appendRE(re);
		}

	}

	private void markInput(String input_file, String output_file)
			throws IOException, FileNotFoundException {
		BufferedReader br = new BufferedReader(new InputStreamReader(
				new FileInputStream(input_file), "gb2312"));
		PrintWriter pw = new PrintWriter(new OutputStreamWriter(
				new FileOutputStream(output_file), "gb2312"));
		WordSeg ws = new WordSeg();
		String line = br.readLine();
		String marked;
		int lineCount = 0;
		while (line != null) {
			System.out
					.println(String.format("processing line %d", ++lineCount));
			marked = markLine(line, ws);
			pw.println(marked);
			line = br.readLine();
		}
		br.close();
		pw.close();

	}

	private String markLine(String line, WordSeg ws) {
		StringBuilder sb = new StringBuilder();
		String[] words = ws.segment(line);
		final int param = Param.MAX_MATCH;
		int max;
		String temp_str = null;
		for (int i = 0; i < words.length; ++i) {
			int j = i;
			boolean found = false;
			max = Math.min(param, words.length - j);
			while (max > 0) {
				temp_str = rebuild(words, j, j + max);
				if (TrainingSet.containsKey(temp_str)) {
					found = true;
					sb.append(String.format("{%s/%s}", temp_str,
							TrainingSet.get(temp_str)));
					i += max - 1;
					break;
				}
				--max;
			}
			if (!found) {
				if (LCMCSet.containsKey(words[j])
						&& LCMCSet.get(words[j]).matches(LCMC_Attr)) {
					sb.append(String.format("{%s/%s}", words[j],
							LCMCSet.get(words[j])));
				} else {
					sb.append(words[j]);
				}
			}

		}
		return sb.toString();
	}

	private String rebuild(final String[] line, final int s, final int e) {
		String ans = "";
		for (int i = s; i < e; ++i) {
			ans += line[i];
		}
		return ans;
	}

	private void processPattern(String temp_file) throws Exception {
		regexReader.readRegex(TempFile);
		NodeList patterns = regexReader.getRoot().getChildNodes();
		for (int i = 0; i < patterns.getLength(); ++i) {
			if (patterns.item(i).getNodeName()
					.equals(RegexReader.PatternNodeName)) {
				NodeList matches = patterns.item(i).getChildNodes();
				String desc = patterns.item(i).getAttributes()
						.getNamedItem(RegexReader.PatternAttrDescName)
						.getNodeValue();
				int arg0 = Integer.valueOf(patterns.item(i).getAttributes()
						.getNamedItem(RegexReader.PatternAttrArg0Name)
						.getNodeValue());
				int arg1 = Integer.valueOf(patterns.item(i).getAttributes()
						.getNamedItem(RegexReader.PatternAttrArg1Name)
						.getNodeValue());
				for (int j = 0; j < matches.getLength(); ++j) {
					if (matches.item(j).getNodeName()
							.equals(RegexReader.MatchNodeName)) {
						processMatch(matches.item(j), desc, arg0, arg1);
					}
				}
			}
		}
	}

	private void processMatch(Node match, String desc, int arg0, int arg1) throws Exception {
		String text = match.getAttributes().getNamedItem(RegexReader.MatchAttrTextName).getNodeValue();
		int doc = Integer.valueOf(match.getAttributes().getNamedItem(RegexReader.MatchAttrDocName).getNodeValue());
		Pattern p = Pattern.compile("(?<=\\{)[^\\{\\}]*/[^\\{\\}]*(?=\\})");
		Matcher m = p.matcher(text);
		String text1 = "";
		String type1 = "";
		String text2 = "";
		String type2 = "";
		int count = 0;
		while(m.find()){
			if(count == arg0){
				String[] tmp = m.group().split("/");
				text1 = tmp[0];
				type1 = tmp[1];
			}else if(count == arg1){
				String[] tmp = m.group().split("/");
				text2 = tmp[0];
				type2 = tmp[1];
			}
			++count;
		}
		RelationSet.add(new RelationEntity(text1, type1, text2, type2, doc, desc));
	}
	private void appendRE(RelationEntity re) {
		XmlGen.appendRelation(re.type1, re.type2, re.text1, re.text2,
				re.doc, re.relation);
	}
}
